package org.itstack.demo.design.agent;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        try {
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:org/itstack/demo/design/**/*.class");
            CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
            for (Resource resource : resources) {
                MetadataReader reader = readerFactory.getMetadataReader(resource);
                AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();

                if (annotationMetadata.hasAnnotation(CustomMapper.class.getName())
                    || annotationMetadata.hasMetaAnnotation(CustomMapper.class.getName())) {
                    Class<?> clazz = Class.forName(reader.getClassMetadata().getClassName());
                    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                    beanDefinition.setBeanClass(MapperFactoryBean.class);
                    beanDefinition.setScope("singleton");
                    beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(clazz);

                    CustomMapper customMapper = AnnotationUtils.findAnnotation(clazz, CustomMapper.class);
                    String customName = customMapper.value();

                    String beanName = StringUtils.isNotBlank(customName) ? customName : StringUtils.uncapitalize(clazz.getSimpleName());

                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
                    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
            throws BeansException {
        // left intentionally blank
    }

}
